package com.sleep.drug_traceability.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sleep.drug_traceability.dao.mapper.DrugConMapper;
import com.sleep.drug_traceability.dao.mapper.DrugManMapper;
import com.sleep.drug_traceability.dao.mapper.DrugSelMapper;
import com.sleep.drug_traceability.dao.mapper.DrugTraMapper;
import com.sleep.drug_traceability.dao.pojo.*;
import com.sleep.drug_traceability.service.LoginService;
import com.sleep.drug_traceability.service.SearchService;
import com.sleep.drug_traceability.vo.*;
import com.sleep.drug_traceability.vo.params.OneParam;
import com.sleep.drug_traceability.vo.params.SearchManParam;
import com.sleep.drug_traceability.vo.params.SearchSelParam;
import com.sleep.drug_traceability.vo.params.TwoParam;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Sleep-6000
 * @date 2022/4/28
 */
@Service
@Transactional
@AllArgsConstructor
public class SearchServiceImpl implements SearchService {

    @Autowired
    private final DrugManMapper drugManMapper;
    @Autowired
    private final DrugTraMapper drugTraMapper;
    @Autowired
    private final LoginService loginService;
    @Autowired
    private final DrugSelMapper drugSelMapper;
    @Autowired
    private final DrugConMapper drugConMapper;

    private final Gateway gateway;

    private final Contract contract;

    @Override
    public Result searchManDrug(SearchManParam searchManParam) {
        String traceableCode = searchManParam.getTraceableCode();
        String drugName = searchManParam.getName();
        String batchNum = searchManParam.getBatchNum();
        Long beginDate = searchManParam.getBeginDate();
        Long endDate = searchManParam.getEndDate();
        String manName = searchManParam.getManName();

        if (StringUtils.isBlank(manName)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<DrugMan> drugManList = drugManMapper.searchManDrug(manName, traceableCode, drugName, batchNum);
        List<SearchManDrugVo> list = new ArrayList<>();
        for (DrugMan drugMan : drugManList) {
            Long mfd = drugMan.getMfd();
            String mfdStr = sdf.format(new Timestamp(mfd));
            if (beginDate != null) {
                String beginStr = sdf.format(new Timestamp(beginDate));
                if (beginStr.compareTo(mfdStr) > 0) {
                    continue;
                }
            }
            if (endDate != null) {
                String endStr = sdf.format(new Timestamp(endDate));
                if (mfdStr.compareTo(endStr) > 0) {
                    continue;
                }
            }
            SearchManDrugVo searchManDrugVo = new SearchManDrugVo();
            searchManDrugVo.setName(drugMan.getName());
            searchManDrugVo.setBatchNum(drugMan.getBatchNum());
            searchManDrugVo.setApprovalNum(drugMan.getApprovalNum());
            searchManDrugVo.setTraceableCode(drugMan.getTraceableCode());

            if (!"".equals(drugMan.getOther())) {
                searchManDrugVo.setOther(drugMan.getOther());
            } else {
                searchManDrugVo.setOther("无");
            }
            searchManDrugVo.setMfd(mfdStr);
            searchManDrugVo.setExp(sdf.format(new Timestamp(drugMan.getExp())));
            searchManDrugVo.setStd(sdf.format(new Timestamp(drugMan.getStd())));
            list.add(searchManDrugVo);
        }

        return Result.success(list);
    }

    @Override
    public Result searchTraDrug(SearchManParam searchTraParam) {
        String traceableCode = searchTraParam.getTraceableCode();
        String drugName = searchTraParam.getName();
        String batchNum = searchTraParam.getBatchNum();
        String manName = searchTraParam.getManName();

        if (StringUtils.isBlank(manName)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }

        List<DrugTra> drugTraList = drugTraMapper.searchTraDrug(manName, traceableCode, drugName, batchNum);

        List<SearchTraDrugVo> searchTraDrugVoList = new ArrayList<>();
        for (DrugTra drugTra : drugTraList) {
            SearchTraDrugVo vo = new SearchTraDrugVo();
            copy(vo, drugTra);
            searchTraDrugVoList.add(vo);
        }

        return Result.success(searchTraDrugVoList);
    }

    @Override
    public Result searchSelDrug(SearchSelParam searchSelParam, String token) {
        String traceableCode = searchSelParam.getTraceableCode();
        String drugName = searchSelParam.getDrugName();
        String batchNum = searchSelParam.getBatchNum();
        Long beginDate = searchSelParam.getBeginDate();
        Long endDate = searchSelParam.getEndDate();
        User user = loginService.checkToken(token);
        if (user == null) {
            return Result.fail(ErrorCode.TOKEN_ERROR.getCode(), ErrorCode.TOKEN_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugSel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugSel::getUserId, user.getId());
        if (!StringUtils.isBlank(traceableCode)) {
            wrapper.eq(DrugSel::getTraceableCode, traceableCode);
        }
        if (!StringUtils.isBlank(drugName)) {
            wrapper.eq(DrugSel::getDrugName, drugName);
        }
        if (!StringUtils.isBlank(batchNum)) {
            wrapper.eq(DrugSel::getBatchNum, batchNum);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<DrugSel> drugSelList = drugSelMapper.selectList(wrapper);
        List<SearchSelDrugVo> list = new ArrayList<>();
        for (DrugSel drugSel : drugSelList) {
            Long ard = drugSel.getArd();
            String ardStr = sdf.format(new Timestamp(ard));
            if (beginDate != null) {
                String beginStr = sdf.format(new Timestamp(beginDate));
                if (beginStr.compareTo(ardStr) > 0) {
                    continue;
                }
            }
            if (endDate != null) {
                String endStr = sdf.format(new Timestamp(endDate));
                if (ardStr.compareTo(endStr) > 0) {
                    continue;
                }
            }
            SearchSelDrugVo vo = new SearchSelDrugVo();
            vo.setTraceableCode(drugSel.getTraceableCode());
            vo.setDrugName(drugSel.getDrugName());
            vo.setBatchNum(drugSel.getBatchNum());
            vo.setManName(drugSel.getManName());
            vo.setArd(ardStr);
            if (!"".equals(drugSel.getOther())) {
                vo.setOther(drugSel.getOther());
            } else {
                vo.setOther("无");
            }
            list.add(vo);
        }
        return Result.success(list);
    }

    @Override
    public Result searchConDrug(SearchSelParam searchConParam, String token) {
        String traceableCode = searchConParam.getTraceableCode();
        String drugName = searchConParam.getDrugName();
        String batchNum = searchConParam.getBatchNum();
        String consumer = searchConParam.getConsumer();
        Long beginDate = searchConParam.getBeginDate();
        Long endDate = searchConParam.getEndDate();
        User user = loginService.checkToken(token);
        if (user == null) {
            return Result.fail(ErrorCode.TOKEN_ERROR.getCode(), ErrorCode.TOKEN_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugCon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugCon::getUserId, user.getId());
        if (!StringUtils.isBlank(traceableCode)) {
            wrapper.eq(DrugCon::getTraceableCode, traceableCode);
        }
        if (!StringUtils.isBlank(drugName)) {
            wrapper.eq(DrugCon::getDrugName, drugName);
        }
        if (!StringUtils.isBlank(batchNum)) {
            wrapper.eq(DrugCon::getBatchNum, batchNum);
        }
        if (!StringUtils.isBlank(consumer)) {
            wrapper.eq(DrugCon::getConsumer, consumer);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<DrugCon> drugConList = drugConMapper.selectList(wrapper);
        List<SearchConDrugVo> list = new ArrayList<>();
        for (DrugCon drugCon : drugConList) {
            Long cond = drugCon.getCond();
            String condStr = sdf.format(new Timestamp(cond));
            if (beginDate != null) {
                String beginStr = sdf.format(new Timestamp(beginDate));
                if (beginStr.compareTo(condStr) > 0) {
                    continue;
                }
            }
            if (endDate != null) {
                String endStr = sdf.format(new Timestamp(endDate));
                if (condStr.compareTo(endStr) > 0) {
                    continue;
                }
            }
            SearchConDrugVo vo = new SearchConDrugVo();
            vo.setTraceableCode(drugCon.getTraceableCode());
            vo.setConsumer(drugCon.getConsumer());
            vo.setDrugName(drugCon.getDrugName());
            vo.setBatchNum(drugCon.getBatchNum());
            vo.setIdNumber(drugCon.getIdNumber());
            vo.setContact(drugCon.getContact());
            vo.setCond(condStr);
            if (!"".equals(drugCon.getOther())) {
                vo.setOther(drugCon.getOther());
            } else {
                vo.setOther("无");
            }
            if (drugCon.getSex() == 0) {
                vo.setSex("男");
            } else if (drugCon.getSex() == 1) {
                vo.setSex("女");
            }
            list.add(vo);
        }
        return Result.success(list);
    }

    @Override
    public Result getManTable(OneParam param) {
        String traceableCode = param.getParam();
        if (StringUtils.isBlank(traceableCode)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugMan> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugMan::getTraceableCode, traceableCode);
        wrapper.last("limit 1");
        DrugMan drugMan = drugManMapper.selectOne(wrapper);
        ManTableVo vo = new ManTableVo();
        vo.setManName(drugMan.getManName());
        vo.setTraceableCode(traceableCode);
        vo.setDrugName(drugMan.getName());
        vo.setBatchNum(drugMan.getBatchNum());
        vo.setApprovalNum(drugMan.getApprovalNum());
        if (!"".equals(drugMan.getOther())) {
            vo.setOther(drugMan.getOther());
        } else {
            vo.setOther("无");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        vo.setMfd(sdf.format(new Timestamp(drugMan.getMfd())));
        vo.setExp(sdf.format(new Timestamp(drugMan.getExp())));
        vo.setStd(sdf.format(new Timestamp(drugMan.getStd())));

        return Result.success(vo);
    }

    @Override
    public Result getTraTable(OneParam param) {
        String traceableCode = param.getParam();
        if (StringUtils.isBlank(traceableCode)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugTra> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugTra::getTraceableCode, traceableCode);
        List<DrugTra> drugTraList = drugTraMapper.selectList(wrapper);
        List<SearchTraDrugVo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (DrugTra drugTra : drugTraList) {
            SearchTraDrugVo vo = new SearchTraDrugVo();
            vo.setTraceableCode(traceableCode);
            vo.setName(drugTra.getDrugName());
            vo.setManName(drugTra.getManName());
            vo.setBatchNum(drugTra.getBatchNum());
            vo.setBuyer(drugTra.getBuyerName());
            if (!"".equals(drugTra.getOther())) {
                vo.setOther(drugTra.getOther());
            } else {
                vo.setOther("无");
            }
            vo.setOstd(sdf.format(new Timestamp(drugTra.getOstd())));
            list.add(vo);
        }
        return Result.success(list);
    }

    @Override
    public Result getSelTable(OneParam param) {
        String traceableCode = param.getParam();
        if (StringUtils.isBlank(traceableCode)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugSel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugSel::getTraceableCode, traceableCode);
        List<DrugSel> drugSelList = drugSelMapper.selectList(wrapper);
        List<SearchSelDrugVo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (DrugSel drugSel : drugSelList) {
            SearchSelDrugVo vo = new SearchSelDrugVo();
            vo.setTraceableCode(traceableCode);
            vo.setDrugName(drugSel.getDrugName());
            vo.setManName(drugSel.getManName());
            vo.setBatchNum(drugSel.getBatchNum());
            vo.setSeller(drugSel.getSeller());
            if (!"".equals(drugSel.getOther())) {
                vo.setOther(drugSel.getOther());
            } else {
                vo.setOther("无");
            }
            vo.setArd(sdf.format(new Timestamp(drugSel.getArd())));
            list.add(vo);
        }
        return Result.success(list);
    }

    @Override
    public Result getConTable(OneParam param) {
        String traceableCode = param.getParam();
        if (StringUtils.isBlank(traceableCode)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        LambdaQueryWrapper<DrugCon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DrugCon::getTraceableCode, traceableCode);
        List<DrugCon> drugSelList = drugConMapper.selectList(wrapper);
        List<SearchConDrugVo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (DrugCon drugCon : drugSelList) {
            SearchConDrugVo vo = new SearchConDrugVo();
            vo.setTraceableCode(traceableCode);
            vo.setConsumer(drugCon.getConsumer());
            vo.setBatchNum(drugCon.getBatchNum());
            vo.setDrugName(drugCon.getDrugName());
            vo.setIdNumber(drugCon.getIdNumber());
            vo.setContact(drugCon.getContact());
            vo.setSeller(drugCon.getSeller());
            if (!"".equals(drugCon.getOther())) {
                vo.setOther(drugCon.getOther());
            } else {
                vo.setOther("无");
            }
            if (drugCon.getSex() == 0) {
                vo.setSex("男");
            } else if (drugCon.getSex() == 1) {
                vo.setSex("女");
            }
            vo.setCond(sdf.format(new Timestamp(drugCon.getCond())));
            list.add(vo);
        }
        return Result.success(list);
    }

    @Override
    public Result trace(OneParam param) throws Exception {
        String traceableCode = param.getParam();
        if (StringUtils.isBlank(traceableCode)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        byte[] bytes = contract.evaluateTransaction("queryDrug", traceableCode);
        String s = org.apache.tomcat.util.codec.binary.StringUtils.newStringUtf8(bytes);

        return Result.success(s);
    }

    @Override
    public Result searchCode(TwoParam twoParam) {
        String manName = twoParam.getFirst();
        String drugName = twoParam.getSecond();
        LambdaQueryWrapper<DrugMan> wrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isBlank(manName)) {
            wrapper.eq(DrugMan::getManName, manName);
        }
        if (!StringUtils.isBlank(drugName)) {
            wrapper.eq(DrugMan::getName, drugName);
        }
        List<DrugMan> drugManList = drugManMapper.selectList(wrapper);
        List<CodeTableVo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (DrugMan drugMan : drugManList) {
            CodeTableVo vo = new CodeTableVo();
            vo.setTraceableCode(drugMan.getTraceableCode());
            vo.setManName(drugMan.getManName());
            vo.setDrugName(drugMan.getName());
            vo.setBatchNum(drugMan.getBatchNum());
            vo.setMfd(sdf.format(new Timestamp(drugMan.getMfd())));
            list.add(vo);
        }
        return Result.success(list);
    }

    private void copy(SearchTraDrugVo searchTraDrugVo, DrugTra drugTra) {
        searchTraDrugVo.setName(drugTra.getDrugName());
        searchTraDrugVo.setManName(drugTra.getManName());
        searchTraDrugVo.setBatchNum(drugTra.getBatchNum());
        searchTraDrugVo.setTraceableCode(drugTra.getTraceableCode());
        searchTraDrugVo.setBuyer(drugTra.getBuyerName());
        if (!"".equals(drugTra.getOther())) {
            searchTraDrugVo.setOther(drugTra.getOther());
        } else {
            searchTraDrugVo.setOther("无");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        searchTraDrugVo.setOstd(sdf.format(new Timestamp(drugTra.getOstd())));
    }
}